// Minimal Unicode Property for Zxx

import Control      from '../mup/Control'
import Format       from '../mup/Format'
import Private_Use  from '../mup/Private_Use'
import Surrogate    from '../mup/Surrogate'
import Unassigned   from '../mup/Unassigned'

import ID_Start     from '../mup/ID_Start'
import ID_Continue  from '../mup/ID_Continue'

import Emoji  from '../mup/Emoji'

const

  UVCHAR  = 0b0001,
  EMOJI   = 0b0010,
  IDC     = 0b0100,
  IDS     = 0b1000,

  Other_ID_Start = Object.freeze(
    [0x1885, 0x1886, 0x2118, 0x212E, 0x309B, 0x309C]
  ),

  codepoints = new Uint8Array(0x110000 / 2).fill(0x11)

Control(clean())
Format(clean())
Private_Use(clean())
Surrogate(clean())
Unassigned(clean())

zero(0x2028) // Line_Separator
zero(0x2029) // Paragraph_Separator

Emoji(property(EMOJI))
ID_Continue(property(IDC))
ID_Start(property(IDS))
Other_ID_Start.forEach(cp => bitwise(cp, IDS))

function zero (cp) {
  let idx = cp >> 1, flag = codepoints[idx]
  if (cp & 1)
    codepoints[idx] = flag & 0xF0
  else
    codepoints[idx] = flag & 0x0F
}

function bitwise (cp, or) {
  let idx = cp >> 1, flag = codepoints[idx]
  if (cp & 1)
    codepoints[idx] = flag | or
  else
    codepoints[idx] = flag | or * 16
}

function clean () {
  return function (...cp) {
    cp.forEach(zero)
    return {
      r: function (first, last) {
        while (first <= last) zero(first++)
        return this
      }
    }
  }
}

function property (cc) {
  return function (...cp) {
    cp.forEach(cp => bitwise(cp, cc))
    return {
      r: function (cp, last) {
        while (cp <= last) bitwise(cp++, cc)
        return this
      }
    }
  }
}

function prop (cp) { // General Category Value
  let prop = codepoints[cp >> 1] | 0
  if (cp & 1)
    return prop & 0x0F
  return prop >> 4
}

function isVChar (cp) {
  return prop(cp) !== 0
}

function isIDC (cp) {
  return (prop(cp) & IDC) === IDC
}

function isIDS (cp) {
  return (prop(cp) & IDS) === IDS
}

export {
  isVChar,
  isIDC,
  isIDS,
  Other_ID_Start,
}
